package io.cici.cc.mybatis.lite.sql_source;

import io.cici.cc.mybatis.lite.executor.parameter.ParameterHandler;
import io.cici.cc.mybatis.lite.mapping.MappedStatement;
import io.cici.cc.mybatis.lite.mapping.ParameterMapping;
import io.cici.cc.mybatis.lite.mapping.Sql;
import io.cici.cc.mybatis.lite.reflection.MetaDataObject;
import io.cici.cc.mybatis.lite.session.Configuration;
import io.cici.cc.mybatis.lite.type.TypeException;
import io.cici.cc.mybatis.lite.type.TypeHandler;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;

public class DefaultParameterHandler implements ParameterHandler {

    private final Object parameterObject;
    private final Sql sql;
    private final Configuration configuration;

    public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, Sql sql) {
        this.configuration = mappedStatement.getConfiguration();
        this.parameterObject = parameterObject;
        this.sql = sql;
    }

    @Override
    public Object getParameterObject() {
        return parameterObject;
    }

    @Override
    public void setParameters(PreparedStatement preparedStatement) {

        List<ParameterMapping> parameterMappingList = sql.getParameterMappingList();
        if (parameterMappingList != null) {
            MetaDataObject metaDataObject = null;
            for (int i = 0; i < parameterMappingList.size(); i++) {
                ParameterMapping parameterMapping = parameterMappingList.get(i);
                {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    String type = parameterMapping.getType();
                    TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
                    if (sql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
                        value = sql.getAdditionalParameter(propertyName);
                    } else if (parameterObject == null) {
                        value = null;
                    } else {
                        if (metaDataObject == null) {
                            metaDataObject = configuration.newMetaDataObject(parameterObject);
                        }
                        value = metaDataObject.getValue(propertyName);
                    }


                    try {
                        typeHandler.set(preparedStatement, i + 1, value);
                    } catch (TypeException | SQLException e) {
                        throw new TypeException(
                                "Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
                    }
                }
            }
        }
    }

}
